package com.tianqu.tms.core.base;

import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.struts.Globals;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;
import org.apache.struts.taglib.html.Constants;

import com.tianqu.tms.core.audit.AuditController;
import com.tianqu.tms.core.audit.AuditLog;
import com.tianqu.tms.core.exception.LoginException;
import com.tianqu.tms.core.exception.NotAuthenticatedException;
import com.tianqu.tms.core.exception.NotServiceTimeException;
import com.tianqu.tms.core.exception.OperationNotValidException;
import com.tianqu.tms.core.exception.PermissionException;
import com.tianqu.tms.core.exception.SessionTimeoutException;
import com.tianqu.tms.core.exception.SystemException;
import com.tianqu.tms.core.exception.TmsException;
import com.tianqu.tms.core.exception.TransactionTokenException;
import com.tianqu.tms.core.security.ServiceController;
import com.tianqu.tms.core.security.TmsUserProfile;
import com.tianqu.tms.core.security.TmsUserProfileFactory;
import com.tianqu.tms.core.util.Registry;
import com.tianqu.tms.core.util.StringUtil;
import com.tianqu.tms.core.util.TmsConstants;

/**
 * TMS Action 的基类
 * @author liugang
 *
 */
public abstract class TmsActionNotTimeout extends Action {

	private Logger logger = Logger.getLogger(TmsActionNotTimeout.class);
	
	/** ***** Session内使用的key *********** */
	public static final String LAST_ACTION_MAPPING = "LAST.ACTION.MAPPING";
	public static final String APPLICATION_USER_CONTEXT_KEY = "applicationContext";
	
	/** ***** HTTP ServletRequest使用的key *********** */
	public static final String USER_ID = "userId"; 
	public static final String USER_PROFILE_KEY = "UserProfile";
	public static final String VIEWHELP = "viewhelp";

	/** ***** 错误ID*********** */
	private static final int MSG_SERVICE_HOUR = 0;
	private static final int MSG_SESSION_ERROR = 1;
	private static final int MSG_MULTIPLE_ACTION = 2;
	private static final int MSG_DIRECT_ACCESS = 3;
	private static final int MSG_AUTHORIZATION_ERROR = 4;
	private static final int MSG_SYSTEM_EXCEPTION = 6;
	private static final int MSG_APPLICATION_EXCEPTION = 7;
	private static final int MSG_USER_CONTEXT_NOT_FOUND = 8;
	private static final String ITEMSPATH="ItemsPath";//获取项目路径

	private static final String[] LOG_MESSAGE_TEXT_EN = {
		"Not in online service hours.",
		"Session Error.",
		"Buttun was clicked more than once.",
		"Page(URL) specified directly withoug logging on or session error.",
		"User is not authorised for this action. Error ID:",
		"Login Error. Error ID:",
		"System Exception.",
		"Tms Application Exception. Error ID:",
		"UserContext not found.",
		"UserContext not power.",
		"Password is not right."
	};	
	
	
	/*-------------------- Public methods --------------------*/

	/**
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return ActionForward
	 * @throws Exception
	 * @roseuid 4051B4250323
	 */
	public ActionForward execute(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
       
		//参数设置
		HttpSession session 	= null;
		TmsUserProfile userProfile = null;
		UserContextImpl uc 		= null;
		
		
		//IE 的回退失效
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Cache-Control", "no-store");
        response.setDateHeader("Expires", 0);
        response.setHeader("Pragma", "no-cache");
        // end
		session = getSession(request);
		String token = (String) session.getAttribute(Globals.TRANSACTION_TOKEN_KEY);
		if (token == null ) {
			logger.debug("Request firset time! Token has been saved!");
			session.setAttribute(LAST_ACTION_MAPPING, mapping);
			saveToken(request);
		}
		
		String attribute = mapping.getAttribute();
		if (null == attribute ) {
			if (isTokenValid(request)) {
				resetToken(request);
				saveToken(request);
				logger.debug("Nomal Request! Going on!");	
			} else {
				boolean failFlag = true;
				String strtoken = request.getParameter(Constants.TOKEN_KEY);
				if (null == strtoken) {
					logger.debug("From Link! Going on!");
					failFlag = false;
				}
				ActionMapping saved_mapping = (ActionMapping) session.getAttribute(LAST_ACTION_MAPPING);
		
				if (!mapping.equals(saved_mapping)) {
					logger.debug("Forward! Going On!!");
					failFlag = false;
				}
				if (failFlag) {
					session.invalidate();
		        	logger.error(getLogMessage(MSG_MULTIPLE_ACTION));
					throw new TransactionTokenException(TmsException.TOKEN_EXCEPTION);
				}
			}
		}
		
		session.removeAttribute(LAST_ACTION_MAPPING);
		session.setAttribute(LAST_ACTION_MAPPING, mapping);
	
		//============================================
		// UserContext设置
		//============================================
		uc = getUserContext(session, request);
		uc.setServletParams(request, response);
		 //获得项目路径
		uc.setAttribute(ITEMSPATH, getItemsPath(request));
        userProfile = getUserProfile(uc);
        if (!isNoValidation(request.getRequestURL().toString())  &&  !validateUserProfile(userProfile)) {
        	logger.error(getLogMessage(MSG_DIRECT_ACCESS));
            throw new NotAuthenticatedException();
        }
		
        try {
			//设置actionform
			setActionFormToContext(uc, form);
			uc.setAttribute(UserContext.ERRORS, null);
			ActionForward forward = doAction(mapping, form, request, response,uc);
			logger.info("=====>"+mapping.getPath());
			
			//UC设置到session
			if (!isNoValidation(request.getRequestURL().toString())){
				request.getSession().setAttribute(APPLICATION_USER_CONTEXT_KEY, uc);
				request.setAttribute(USER_PROFILE_KEY, uc.getUserProfile());
				request.setAttribute("funcId", this.getFuncId(request, mapping, uc.getUserProfile()));
            }
			//页面跳转
			return forward;

		} catch (PermissionException ce) {
			logger.warn(getLogMessage(MSG_AUTHORIZATION_ERROR) + ce.getExceptionId());
			setErrorsToRequest(request, ce.getExceptionId(), null);
			accessFialLogForAudit(userProfile, getFuncId(request, mapping, uc.getUserProfile()));
			throw new PermissionException(ce.getExceptionId(), ce);

		}catch (SessionTimeoutException ste) {
			throw new SessionTimeoutException();

		} catch (TransactionTokenException te) {
			setErrorsToRequest(request, te.getExceptionId(), null);
			throw new TransactionTokenException(te.getExceptionId(), te);

		} catch (OperationNotValidException te) {
   			setErrorsToRequest(request, te.getExceptionId(), null);
   			throw new OperationNotValidException(te.getExceptionId(), te);
   			
		} catch (SystemException e) {
			logger.error(getLogMessage(MSG_SYSTEM_EXCEPTION), e);		
			throw e;
		
		}catch (TmsException ae) {
			logger.error(getLogMessage(MSG_APPLICATION_EXCEPTION) + ae.getExceptionId());
			setErrorsToRequest(request, ae.getExceptionId(), ae.getErrorParams());
			setListErrorsToRequest(request, ae.getActionErrors());
			return mapping.getInputForward();

		} catch (Exception e) {
			logger.error(getLogMessage(MSG_SYSTEM_EXCEPTION), e);
			setErrorsToRequest(request, TmsException.SYS_EXCEPTION, null);
			throw new SystemException(TmsException.SYS_EXCEPTION, e);
		}
	}

	
	
	public ActionForward isToken(ActionMapping mapping, 
			HttpServletRequest request)
			throws Exception 
	{
		 if(!isTokenValid(request)){//如果两个值相等,即表单重复提交
			 this.resetToken(request);
				 setErrorsToRequest(request, TmsConstants.I0005 ,null);
				 return mapping.findForward(TmsConstants.SUCCESS);
				 }else{//当用户首次提交时返!isTokenValid()返回true
				//将用户session中的token清空
				 this.saveToken(request);
				 }
		return null;
		
	}
	/**
	 * set action msg
	 * 
	 * @param request
	 */
	protected void setMessagesToRequest(HttpServletRequest request,
			String msgKey, String[] msgParam) {
		if (msgKey == null) {
			return;
		}
		ActionMessages messages = new ActionMessages();
		messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(msgKey,
				msgParam));

		saveMessages(request, messages);

	}

	/**
	 * set action errors
	 * 
	 * @param request
	 */
	protected void setErrorsToRequest(HttpServletRequest request, String errKey,
			String[] errParams) {
		if (errKey == null) {
			return;
		}
		ActionErrors errors = new ActionErrors();
		errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(errKey,
				errParams));
		addErrors(request, errors);
	}

	/**
	 * 
	 * @param request
	 * @param listErrors
	 */
	private void setListErrorsToRequest(HttpServletRequest request,List<ActionMessage> listErrors) {
		if (listErrors != null && listErrors.size() > 0) {
			ActionErrors errors = new ActionErrors();
			for (int i = 0; i < listErrors.size(); i++) {
				errors.add(ActionMessages.GLOBAL_MESSAGE,
						(ActionMessage) listErrors.get(i));
			}
			addErrors(request, errors);
		}
	}

	/**
	 * 
	 * @param request
	 * @return
	 */
	protected HttpSession getSession(HttpServletRequest request) {
		return request.getSession(false);
	}

	/**
	 * 
	 * @param session
	 * @return
	 */
	protected boolean validateSession(HttpSession session) {
		if (session.isNew()) {
			UserContext uc = (UserContext) session.getAttribute(APPLICATION_USER_CONTEXT_KEY);
			if (null== uc) {
				return false;
			}
		}
		return true;
	}

	/**
	 * 
	 * @param request
	 * @param response
	 * @return
	 */
	protected UserContextImpl validateUserContext(HttpServletRequest request,
			HttpServletResponse response) {
		HttpSession session = request.getSession(true);
		UserContextImpl uc = null;
		Object ucObj = session
				.getAttribute(APPLICATION_USER_CONTEXT_KEY);
		if (ucObj == null) {
			uc = new UserContextImpl();
		} else {
			uc = (UserContextImpl) ucObj;
		}
		uc.setServletParams(request, response);
		return uc;
	}

	
    /**
     * 
     * @param session
     * @param request
     * @return
     * @throws Exception
     */
    protected UserContextImpl getUserContext(HttpSession session,
            HttpServletRequest request) throws Exception {

        UserContextImpl uc = (UserContextImpl) session
                .getAttribute(APPLICATION_USER_CONTEXT_KEY);

        if (null == uc)  uc = new UserContextImpl();
        return uc;
    }
    /**
     * ��� TmsUserProfile
     * @param uc
     * @return
     */
    protected TmsUserProfile getUserProfile(UserContextImpl uc) {
        return uc.getUserProfile();
    }
    
	/**
	 * 
	 * @param uc
	 * @throws Exception
	 */
	protected void setUserProfile(UserContextImpl uc) throws Exception {
		String userId = uc.getHttpServletRequest().getParameter(USER_ID);
		TmsUserProfile userProfile = uc.getUserProfile();
		if (userId == null) {
				throw new LoginException(LoginException.LOGIN_EXCEPTION, this.getClass().getName() + ".valudateLogin");
		} else {
			TmsUserProfileFactory userProfileFactory = TmsUserProfileFactory.getInstance();
			userProfile = userProfileFactory.getUserProfile(userId);
		}
		if (null == userProfile) {
				throw new LoginException(LoginException.LOGIN_EXCEPTION, this.getClass().getName() + ".valudateLogin");
		}
		uc.setUserProfile(userProfile);
	}

    /**
     * 验证用户信息
     * @param userProfile
     * @return
     */
    protected boolean validateUserProfile(TmsUserProfile userProfile) {
        return !(userProfile == null || TmsConstants.ZERO == userProfile.getUniqueId());
    }

	/**
	 * 
	 * @param uc
	 * @param actionform
	 */
	protected void setActionFormToContext(UserContext uc, ActionForm actionform) {
		uc.setInputForm(actionform);
	}
	 
	/**
	 * 
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @param uc
	 * @return
	 * @throws Exception
	 */
	protected abstract ActionForward doAction(ActionMapping mapping,
			ActionForm form, HttpServletRequest request,
			HttpServletResponse response, UserContext uc) throws Exception;

	/**
	 * 
	 * @param mapping
	 * @return
	 */
	protected String getFuncId(HttpServletRequest request, ActionMapping mapping, TmsUserProfile userProfile) {
		String funcId = ((TmsActionMapping) mapping).getFuncId();
		if (StringUtil.isNullOrBlank(funcId)) {
			funcId = userProfile.getFuncId();
		} else {
			userProfile.setFuncId(funcId);
		}
		return funcId;
	}

	/**
	 * 验证系统是否处于服务时间
	 * @return
	 * @throws Exception
	 */
	private boolean validateServiceTime() throws Exception {
		ServiceController srvController = ServiceController.getInstance(); 
		
		return srvController.onService();
	}
	
	/**
	 * ȥ����û��Ȩ�޵Ĺ��ܵ�log���
	 * @param profile
	 * @param funcId
	 */
	private void accessFialLogForAudit(TmsUserProfile profile, String funcId) {
		AuditLog log = new AuditLog();
		log.setTarget(this.getClass().getName());

		StringBuffer msg = new StringBuffer();;
		log.setAccessKey(msg.toString());
		log.setIllegalAccess("Y");
		
		AuditController audit = AuditController.getInstance();
		try {
			audit.log(log);
		} catch (Exception e) {
			logger.error(this.getClass().getName(), e);
		}
	}
	/**
	 * 
	 * @param msgId
	 * @return
	 */
	private String getLogMessage(int msgId) {
		String[] logMessageText;
		logMessageText = LOG_MESSAGE_TEXT_EN;
		return logMessageText[msgId];
	}
     /**
      * 获得项目路径
      * @param request
      * @return
      */
	private String getItemsPath(HttpServletRequest request){
		String requestPath = request.getRealPath("/");
		String context =Registry.getConfig(TmsConstants.CONTEXT_ROOT_KEY);
		String path =requestPath.substring(0,requestPath.length()-context.length());
		System.out.println(path);
		return path;
	}
	
	private boolean isNoValidation(String url){
		if(StringUtil.isNullOrBlank(url)) return false;
		return url.contains("carInformationShow") || url.contains("findCarIndex")
				|| url.contains("findCarPriceList") 
				|| url.contains("findCarBrandIndex") || url.contains("findCarPriceIndex")
				|| url.contains("findCarPriceDetail") || url.contains("findCarRecommendedList")
				|| url.contains("findCarBrandCountList") || url.contains("findCarBrandList")
				|| url.contains("findCarPriceList") || url.contains("findCarBrandDetail") || url.contains("findCarRecommendedDetail");
	}
}